package com.dz.syndata.config;

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashSet;
import java.util.Set;

/**
 *redis配置三个连接源
 * @Author guoxx
 */
@Configuration
public class RedisJedisConfig {
    // r1 redis 配置信息
    @Value("${spring.redis.r1.host:}")
    private String r1Host;
    @Value("${spring.redis.r1.port:}")
    private Integer r1Port;
    @Value("${spring.redis.r1.password:}")
    private String r1Password;
    @Value("${spring.redis.r1.database:}")
    private Integer r1Database;
    // r2 redis 配置信息
    @Value("${spring.redis.r2.host:}")
    private String r2Host;
    @Value("${spring.redis.r2.port:}")
    private Integer r2Port;
    @Value("${spring.redis.r2.password:}")
    private String r2Password;
    @Value("${spring.redis.r2.database:}")
    private Integer r2Database;
    /**
     * connectionFactory 配置工厂
     */
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    public RedisConnectionFactory connectionFactory(
            RedisStandaloneConfiguration redisStandaloneConfiguration,
            RedisClusterConfiguration redisClusterConfiguration,
            JedisPoolConfig jedisPoolConfig) {
        if (redisStandaloneConfiguration == null && redisClusterConfiguration == null) {
            System.out.println("==============请添加redis配置================");
            logger.error("==============请添加redis配置================");
            return null;
        }

        JedisConnectionFactory jedisConnectionFactory = null;

        if (redisStandaloneConfiguration != null) {
            jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
        } else {
            jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
        }
        jedisConnectionFactory.afterPropertiesSet();

        // 检查是否可用
        RedisConnection connection = null;
        try {
            connection = jedisConnectionFactory.getConnection();
            System.out.println("reids是否可用:" + !connection.isClosed());
        } catch(Exception e) {
            System.out.println("reids不可用，请检查组件是否启动:"+e);
            logger.error("reids不可用，请检查组件是否启动:"+e);
        } finally {
            connection.close();
        }

        return jedisConnectionFactory;
    }

    /**
     * poolConfig连接池配置 只有集群时使用
     * @return
     */
    public JedisPoolConfig poolConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(10200);
        config.setMaxIdle(5000);
        config.setMinIdle(800);
        config.setMaxWaitMillis(10000);         // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
        config.setTestOnBorrow(true);           // 在获取连接的时候检查有效性, 默认false
        config.setTestOnReturn(false);          // 调用returnObject方法时，是否进行有效检查
        config.setTestWhileIdle(true);          // Idle时进行连接扫描
        config.setTimeBetweenEvictionRunsMillis(30000);     // 表示idle object evitor两次扫描之间要sleep的毫秒数
        config.setNumTestsPerEvictionRun(10);               // 表示idle object evitor每次扫描的最多的对象数
        config.setMinEvictableIdleTimeMillis(60000);        // 表示一个对象至少停留在idle状态的最短时间，然后才能被idle object evitor扫描并驱逐；这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
        return config;
    }
    /**
     * redisStandaloneConfiguration 单机版配置
     * @param host
     * @param port
     * @param password
     * @param index
     * @return
     */
    public RedisStandaloneConfiguration redisStandaloneConfiguration(String host, int port, String password, int index) {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host, port);

        if (StrUtil.isNotBlank(password)) {
            redisStandaloneConfiguration.setPassword(password);
        }
        if (index != 0) {
            redisStandaloneConfiguration.setDatabase(index);
        }
        return redisStandaloneConfiguration;
    }

    /**
     * redisClusterConfiguration 集群配置
     * @param clusterNodes
     * @param password
     * @return
     */
    public RedisClusterConfiguration redisClusterConfiguration(String clusterNodes, String password) {
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
        // Set<RedisNode> clusterNodes
        String[] serverArray = clusterNodes.split(",");
        Set<RedisNode> nodes = new HashSet<RedisNode>();
        for (String ipPort : serverArray) {
            String[] ipAndPort = ipPort.split(":");
            nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
        }
        redisClusterConfiguration.setClusterNodes(nodes);
        redisClusterConfiguration.setMaxRedirects(6);
        if (StrUtil.isNotBlank(password)) {
            redisClusterConfiguration.setPassword(RedisPassword.of(password));
        }
        return redisClusterConfiguration;
    }
    @Bean(name = "redisR1Template")
    public RedisTemplate<String, Object> redisR1Template() {
        RedisTemplate<String, Object> template;
        RedisStandaloneConfiguration redisStandaloneConfiguration;
        RedisClusterConfiguration redisClusterConfiguration;
        template = new RedisTemplate<>();
        try {

            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            redisStandaloneConfiguration = null;
            redisClusterConfiguration = null;
            template.setEnableTransactionSupport(false);
            template.setKeySerializer(stringRedisSerializer);
            // 如果手动将Value转换成了JSON，就不要再用JSON序列化器了。
            template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
//        template.setValueSerializer(stringRedisSerializer);
            if (StrUtil.isNotBlank(r1Host) ) {
                redisStandaloneConfiguration = redisStandaloneConfiguration(r1Host, r1Port, r1Password, r1Database);
            }
        } finally {
            //手动释放连接
//            RedisConnectionUtils.unbindConnection(template.getConnectionFactory());
        }

        System.out.println("=========================R1 redis信息 开始===============================");
        template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig()));
        System.out.println("=========================R1 redis信息 结束===============================");

        return template;
    }

    @Bean(name = "redisR2Template")
    public RedisTemplate<String, Object> redisR2Template() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        try {
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            RedisStandaloneConfiguration redisStandaloneConfiguration = null;
            RedisClusterConfiguration redisClusterConfiguration = null;
            template.setEnableTransactionSupport(false);
            template.setKeySerializer(stringRedisSerializer);
            // 如果手动将Value转换成了JSON，就不要再用JSON序列化器了。
            template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
//        template.setValueSerializer(stringRedisSerializer);
            if (StrUtil.isNotBlank(r2Host) ) {
                redisStandaloneConfiguration = redisStandaloneConfiguration(r2Host, r2Port, r2Password, r2Database);
            }
            System.out.println("=========================R2 redis信息 开始===============================");
            template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig()));
            System.out.println("=========================R2 redis信息 结束===============================");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }

        return template;
    }


}
